import re
import logging
import os
import ConfigParser
class HmmerHit:

    def __init__(self):
        self._sequence = None
        self._description = None
        self._expectedDomainCount = None
        self._usedDomainCount = None
        self._overallMatch = None
        self._bestDomainMatch = None

    def __init__(self, line):
        bits = re.split("\s+", line.strip())
        overall = DomainMatch()
        overall.setEvalue(bits[0])
        overall.setScore(bits[1])
        overall.setBias(bits[2])
        self.setOverallMatch(overall)
        best = DomainMatch()
        best.setEvalue(bits[3])
        best.setScore(bits[4])
        best.setBias(bits[5])
        self.setBestDomainMatch(best)
        self.setExpectedDomainCount(bits[6])
        self.setUsedDomainCount(bits[7])
        self.setSequence(bits[8])
        self.setDescription(bits[9])

    def getSequence(self):
        return self._sequence
    def setSequence(self, sequence):
        self._sequence = sequence

    def getDescription(self):
        return self._description
    def setDescription(self, description):
        self._description = description

    def getExpectedDomainCount(self):
        return self._expectedDomainCount
    def setExpectedDomainCount(self, expectedDomainCount):
        self._expectedDomainCount = float(expectedDomainCount)

    def getUsedDomainCount(self):
        return self._usedDomainCount
    def setUsedDomainCount(self, usedDomainCount):
        self._usedDomainCount = float(usedDomainCount)

    def getOverallMatch(self):
        return self._overallMatch
    def setOverallMatch(self, overallMatch):
        self._overallMatch = overallMatch

    def getBestDomainMatch(self):
        return self._bestDomainMatch
    def setBestDomainMatch(self, bestDomainMatch):
        self._bestDomainMatch = bestDomainMatch

    sequence = property(getSequence, setSequence)
    description = property(getDescription, setDescription)
    expectedDomainCount = property(getExpectedDomainCount, setExpectedDomainCount)
    usedDomainCount = property(getUsedDomainCount, setUsedDomainCount)
    bestDomainMatch = property(getBestDomainMatch, setBestDomainMatch)
    overallMatch = property(getOverallMatch, setOverallMatch)

    def validate(self):
        rtnValue = None
        if(self.getOverallMatch().getEvalue() <0.01  and self.getBestDomainMatch().getEvalue() <0.01):
            rtnValue = HmmerHitValidation.HOMOLOGOUS
        elif(self.getOverallMatch().getEvalue() <0.01 and self.getBestDomainMatch().getEvalue() > 0.01 and (self.getExpectedDomainCount()/self.getUsedDomainCount() <= 1 or self.getExpectedDomainCount()/self.getUsedDomainCount() >=0.8)):
            rtnValue = HmmerHitValidation.MULTIDOMAIN
        else:
            rtnValue= HmmerHitValidation.REPETITIOUS
        return rtnValue


class DomainMatch(object):

    def __init__(self):
        self._eValue = None
        self._score = None
        self._bias = None

    def getEvalue(self):
        return self._eValue
    def setEvalue(self, eValue):
        self._eValue = float(eValue)

    def getScore(self):
        return self._score
    def setScore(self, score):
        self._score = float(score)

    def getBias(self):
        return self._bias
    def setBias(self, bias):
        self._bias = float(bias)

    bias = property(getBias, setBias)
    score = property(getScore, setScore)
    eValue = property(getEvalue, setEvalue)

class HmmerHitValidation:
    unknown = 0
    HOMOLOGOUS = 1
    MULTIDOMAIN = 2
    REPETITIOUS = 3

class HIK:
    """ This is a Homology Identification Kit object """
    geneName = None
    cog = None
    hmm = None
    hmmFile = None
    stringFasta =None
    stringHmm = None
    consensus = None
    proteinProfile = None

class DatabaseObj:
    '''this is an object to represent a database'''
    name = None
    location = None


class HomologSearch:
    def __init__(self, hik, db):
        self._hik = hik
        self._db = db
        self._storage = "%s.%s.vs.%s.txt" %(hik.geneName, hik.cog, db.name)
        self._goodHits = []
        self._badHits = []

    @property
    def hik(self):
        return self._hik
    @property
    def db(self):
        return self._db
    @property
    def storage(self):
        return self._storage
    @property
    def goodHits(self):
        return self._goodHits
    @property
    def badHits(self):
        return self._badHits


class Homolog:
    stringHit =None
    species = None
    fragment = None




class BlastHit:
    '''Class to represent a blast hit from a blast2table.with.frames.pl output'''
    def __init__(self, line):
        bits = re.split('\t', line.strip())
        self._query = bits[0]
        self._subject = bits[1]
        #self._queryLength = bits[2]
        m = re.match('\d+\.(.*)', bits[1])
        if m:
            self._species = m.group(1)
        else:
            self._species = 'Unknown'
        #self._pctId = bits[2]
        #self._frame = bits[5]
        #self._expect = bits[13]
        #self._bitScore = bits[14]

    @property
    def query(self):
        return self._query
    @property
    def subject(self):
        return self._subject
    #@property
    #def queryLength(self):
        #return self._queryLength
    @property
    def species(self):
        return self._species
    @property
    def pctId(self):
        return self._pctId
    #@property
   # def frame(self):
        #return self._frame
    #@property
    #def expect(self):
        #return self._expect
    #@property
    #def bitScore(self):
        #return self._bitScore

class HomologFinderConfig:

    config = ConfigParser.RawConfigParser()
    config.read('HomologFinder.conf')
    HOME = config.get('homologfinder', 'HOME')
    HMM_STORE = config.get('homologfinder', 'HMM_STORE')
    SCRATCH = config.get('homologfinder', 'SCRATCH')
    CONSENSUS_STORE = config.get('homologfinder', 'CONSENSUS_STORE')
    PP_STORE = config.get('homologfinder', 'PP_STORE')
    TOOL_STORE = config.get('homologfinder', 'TOOL_STORE')
    PICKLE_STORE = config.get('homologfinder', 'PICKLE_STORE')



    STRING_HOME = config.get('homologfinder', 'STRING_HOME')
    MAFFT = config.get('homologfinder', 'MAFFT')
    MAFFT_THREAD = config.get('homologfinder', 'MAFFT_THREAD')
    MAX_HOMOLOG_COUNT=config.getint('homologfinder', 'MAX_HOMOLOG_COUNT')
    HMMER_HOME=config.get('homologfinder', 'HMMER_HOME')
    BLAST_HOME=config.get('homologfinder', 'BLAST_HOME')
    PFAM_HOME_URL=config.get('homologfinder', 'PFAM_HOME_URL')
    PROCESSORS=config.get('homologfinder', 'PROCESSORS')
    WORKER_COUNT=config.get('homologfinder', 'WORKER_COUNT')
    PERFORM_BLAST=bool(int(config.get('homologfinder', 'PERFORM_BLAST')))


    #STRING_HOME = "/data/STRING/"
    STRING_SEQS = STRING_HOME + "protein.sequences.v8.2.fa"

    #MAFFT = "/usr/local/bin/mafft"
    #PFAM_HOME_URL = "/data/pfam/Pfam-A.hmm"

    HMMER_SEARCH = HMMER_HOME + "hmmsearch"
    HMMER_BUILD = HMMER_HOME + "hmmbuild"
    HMMER_FETCH = HMMER_HOME + "hmmfetch"
    HMMER_EMIT = HMMER_HOME + "hmmemit"

    BLAST_FORMATDB = BLAST_HOME + "formatdb"
    BLAST_BLASTPGP = BLAST_HOME + "blastpgp"
    BLAST_BLASTALL = BLAST_HOME + "blastall"
    BLAST_FASTACMD = BLAST_HOME + "fastacmd"

class Error(Exception):
    """Base class for exceptions in this module."""
    pass

class NoSequencesToExtractError(Error):
    def __init__(self, message):
         self.value = message
    @property
    def message(self):
        return self.message